﻿using System;

namespace Mbs.Messaging.Imp
{
    [Serializable]
    public class Executor<TMessage> : MarshalByRefObject, IExecutor<TMessage>
    {
        public ISubject<TMessage> Subject { get; set; }
        public IMessageListnerManager ListnerManager { get; set; }
        public IDelegateInvoker DelegateInvoker { get; set; }

        public void Execute()
        {
            if (Subject.Closed)
                return;

            var handlers = Subject.Subscriber.Observers;
            if (handlers != null && handlers.Length > 0)
                DoExecute();
        }

       protected virtual void DoExecute()
        {
            if (Subject.Queue.Count == 0)
                return;

            var pair = Subject.Queue.Dequeue();
            var sender = pair.Key;
            var message = pair.Value;

            var packet = new SendingEventArgs (sender,message,Subject.Name);

            ListnerManager.OnSending(sender, packet);

            if (packet.Canceled)
            {
                ListnerManager.OnSent(sender, packet);
                return;
            }
             
            var e = new PreFilterEventArgs<TMessage>(sender, message, Subject.Name);
            
            DelegateInvoker.Invoke<TMessage>(Subject.Subscriber.PreFilters, e);

            if (e.Canceled)
            {
                ListnerManager.OnSent(sender, packet);
                return;
            }

            DoExecute(sender, message);
            ListnerManager.OnSent(sender, packet);
        }



        protected virtual void DoExecute(object sender, TMessage message)
        {
            var handlers = Subject.Subscriber.Observers;
 
            var filters = Subject.Subscriber.Filters;

            foreach (var item in handlers)
            {
                if (!DoExecute(message, filters, sender, item))
                    break;
            }
        }

        protected bool DoExecute(TMessage message, FilterHandler<TMessage>[] filters, object sender, ObserverHandler<TMessage> handle)
        {
            var e = new ReceivingEventArgs (sender,message, handle.Target, Subject.Name );
            var fe = new FilterEventArgs<TMessage>(sender, message);
            try
            {
                ListnerManager.OnReceiving(sender, e);
                if (!e.Ignored)
                    DelegateInvoker.Invoke<TMessage>(filters, handle, fe);
                return true;
            }
            catch (Exception ex)
            {
                var re = new ReceivingExceptionEventArgs (sender, message, ex,Subject.Name );
                ListnerManager.OnReceivingException(fe.Sender, re);
                return !re.Canceled; 
            }
            finally
            {
                ListnerManager.OnReceived(sender, new MessageEventArgs (sender, message, Subject.Name ));
                e = null;
            }
        }

        public override object InitializeLifetimeService()
        {
            return null;
        }
    }
}
